package com.sunshine.homepage.service.impl;

import com.sunshine.homepage.dao.ProductsDao;
import com.sunshine.homepage.entity.Products;
import com.sunshine.homepage.service.InventoryService;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RAtomicLong;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import sunshine.commcon.util.entity.Result;

import javax.annotation.Resource;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
public class InventoryServiceImpl implements InventoryService {
    
    @Resource
    private RedissonClient redissonClient;
    
    @Resource
    private RedisTemplate<String, Object> redisTemplate;
    
    @Resource
    private ProductsDao productsDao;
    
    // Redis中库存的key前缀
    private static final String STOCK_PREFIX = "product:stock:";
    
    // Redis中预扣减库存的key前缀
    private static final String PRE_DEDUCT_STOCK_PREFIX = "product:pre_deduct_stock:";
    
    @Override
    public Result<Boolean> checkStock(Long productId, Integer quantity) {
        try {
            // 获取商品库存
            Long stock = getStockFromRedis(productId);
            if (stock == null) {
                // 如果Redis中没有库存信息，则从数据库同步
                syncStockToRedis(productId);
                stock = getStockFromRedis(productId);
            }
            
            // 检查库存是否充足
            if (stock != null && stock >= quantity) {
                return Result.ok(true);
            } else {
                return Result.ok(false);
            }
        } catch (Exception e) {
            log.error("检查商品库存时发生异常: 商品ID={}, 数量={}", productId, quantity, e);
            return Result.fail("检查库存失败");
        }
    }
    
    @Override
    @Transactional
    public Result<Boolean> deductStock(Long productId, Integer quantity) {
        try {
            // 先检查库存是否充足
            Result<Boolean> checkResult = checkStock(productId, quantity);
            if (!checkResult.getData()) {
                return Result.fail("商品库存不足");
            }
            
            // 使用Redisson的原子操作扣减库存
            String stockKey = STOCK_PREFIX + productId;
            String preDeductKey = PRE_DEDUCT_STOCK_PREFIX + productId;
            
            RAtomicLong stockAtomic = redissonClient.getAtomicLong(stockKey);
            RAtomicLong preDeductAtomic = redissonClient.getAtomicLong(preDeductKey);
            
            // 原子性地扣减库存并增加预扣减库存
            Long currentStock = stockAtomic.get();
            if (currentStock >= quantity) {
                stockAtomic.addAndGet(-quantity);
                preDeductAtomic.addAndGet(quantity);
                return Result.ok(true);
            } else {
                return Result.fail("商品库存不足");
            }
        } catch (Exception e) {
            log.error("扣减商品库存时发生异常: 商品ID={}, 数量={}", productId, quantity, e);
            return Result.fail("扣减库存失败");
        }
    }
    
    @Override
    @Transactional
    public Result<Boolean> confirmDeductStock(Long productId, Integer quantity) {
        try {
            // 确认扣减预扣减的库存
            String preDeductKey = PRE_DEDUCT_STOCK_PREFIX + productId;
            RAtomicLong preDeductAtomic = redissonClient.getAtomicLong(preDeductKey);
            
            // 减少预扣减库存
            Long currentPreDeduct = preDeductAtomic.get();
            if (currentPreDeduct >= quantity) {
                preDeductAtomic.addAndGet(-quantity);
                
                // 同步更新数据库库存
                Products product = productsDao.queryById(productId);
                if (product != null) {
                    product.setStock(product.getStock() - quantity);
                    productsDao.update(product);
                }
                
                return Result.ok(true);
            } else {
                return Result.fail("预扣减库存不足");
            }
        } catch (Exception e) {
            log.error("确认扣减商品库存时发生异常: 商品ID={}, 数量={}", productId, quantity, e);
            return Result.fail("确认扣减库存失败");
        }
    }
    
    @Override
    public Result<Boolean> releaseStock(Long productId, Integer quantity) {
        try {
            // 释放预扣减的库存
            String stockKey = STOCK_PREFIX + productId;
            String preDeductKey = PRE_DEDUCT_STOCK_PREFIX + productId;
            
            RAtomicLong stockAtomic = redissonClient.getAtomicLong(stockKey);
            RAtomicLong preDeductAtomic = redissonClient.getAtomicLong(preDeductKey);
            
            // 增加库存并减少预扣减库存
            stockAtomic.addAndGet(quantity);
            preDeductAtomic.addAndGet(-quantity);
            
            return Result.ok(true);
        } catch (Exception e) {
            log.error("释放商品库存时发生异常: 商品ID={}, 数量={}", productId, quantity, e);
            return Result.fail("释放库存失败");
        }
    }
    
    @Override
    public Result<Boolean> syncStockToRedis(Long productId) {
        try {
            // 从数据库获取商品信息
            Products product = productsDao.queryById(productId);
            if (product == null) {
                return Result.fail("商品不存在");
            }
            
            // 同步库存到Redis
            String stockKey = STOCK_PREFIX + productId;
            RAtomicLong stockAtomic = redissonClient.getAtomicLong(stockKey);
            stockAtomic.set(product.getStock());
            
            // 初始化预扣减库存为0
            String preDeductKey = PRE_DEDUCT_STOCK_PREFIX + productId;
            RAtomicLong preDeductAtomic = redissonClient.getAtomicLong(preDeductKey);
            preDeductAtomic.set(0);
            
            log.info("同步商品库存到Redis成功: 商品ID={}, 库存={}", productId, product.getStock());
            return Result.ok(true);
        } catch (Exception e) {
            log.error("同步商品库存到Redis时发生异常: 商品ID={}", productId, e);
            return Result.fail("同步库存失败");
        }
    }
    
    /**
     * 从Redis获取商品库存
     * @param productId 商品ID
     * @return 库存数量
     */
    private Long getStockFromRedis(Long productId) {
        try {
            String stockKey = STOCK_PREFIX + productId;
            RAtomicLong stockAtomic = redissonClient.getAtomicLong(stockKey);
            return stockAtomic.get();
        } catch (Exception e) {
            log.error("从Redis获取商品库存时发生异常: 商品ID={}", productId, e);
            return null;
        }
    }
}